#include "query.h"
#include "logger.h"
#include "fusexx.h"

using namespace PGSTD;
using namespace pqxx;


int PostgreDB::query_inode_full(connection* conn, const char* path, int* inode, int* id)
{
    char sql_buf[MAX_SQL_BUF];
   
    string full_path = ((path[0] == '/') ? &path[1] : path);
    if(full_path != "" && full_path[full_path.size()-1] != '/') full_path += '/';
    
    string sql_from = "tree AS t0";
    string sql_where = "t0.parent is NULL";
    
    int pos = 0, pos2;
    int level = 0;

    while( (pos2 = full_path.find('/', pos)) != (int)string::npos ) {
        level++;
        string curr_name = full_path.substr(pos, pos2 - pos);
       
        snprintf(sql_buf, MAX_SQL_BUF, " LEFT JOIN tree AS t%d ON t%d.id = t%d.parent", level, level-1, level);        
        sql_from += sql_buf;
           
        snprintf(sql_buf, MAX_SQL_BUF, " AND t%d.name = '%s'", level, sqlesc(curr_name).c_str()); 
        sql_where += sql_buf;

        pos = pos2 + 1;
    }    

    sprintf(sql_buf, "SELECT t%d.inode, t%d.id FROM %s WHERE %s", level, level, sql_from.c_str(), sql_where.c_str());

    try {
        work action(*conn, "query_inode");

        log::debug("PostgreDB::query_inode_full(): SQL=%s", sql_buf);

        result res = action.exec(sql_buf);
        if(res.size() == 0) {
            log::error("PostgreDB::query_inode_full(): can not get tree entry corresponding to %s", path);
            return -ENOENT;
        }
        
        action.commit();
       
        if(inode) res[0][0].to(*inode);
        if(id) res[0][1].to(*id);

        log::info("PostgreDB::query_inode_full(): found tree entry for %s", path);

        return 0;
    }
    catch(const sql_error& e) {
        log::error("PostgreDB::query_inode_full(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_inode_full(): EXCEPTION (%s)", e.what());
       return -EIO;
    }

}




int PostgreDB::query_inode(connection* conn, const char* path)
{   log::debug("PostgreDB::query_inode(\"%s\") called", path);

    int inode;
    int ret = query_inode_full(conn, path, &inode, NULL);
    
    if(ret < 0) {
        log::error("PostgreDB::query_inode(): can not get inode for %s", path);
        return ret;
    }
    else {
        log::debug("PostgreDB::query_inode(): inode of %s is %d\n", path, inode);
        return inode;
    }
}


int PostgreDB::query_id(connection* conn, const char* path)
{   log::debug("PostgreDB::query_id(\"%s\") called", path);

    int id;
    int ret = query_inode_full(conn, path, NULL, &id);

    if(ret < 0) {
        log::error("PostgreDB::query_id(): can not get parent ID for %s", path);
        return ret;
    }
    else {
        log::debug("PostgreDB::query_id(): parent ID of %s is %d\n", path, id);
        return id;
    }
}


ssize_t PostgreDB::query_size(pqxx::connection* conn, int inode)
{
    char sql_buf[MAX_SQL_BUF];
    ssize_t size;

    snprintf(sql_buf, MAX_SQL_BUF, "SELECT size FROM inodes WHERE inode=%d", inode);
    
    try {
        work action(*conn, "query_size");
        
        log::debug("PostgreDB::query_size(): SQL=%s", sql_buf);

        result res = action.exec(sql_buf);
        
        if(res.size() != 1 || !res[0][0].to(size) ) {
            log::error("PostgreDB::query_size(): %s did not return valid size for inode %d", sql_buf, inode);
            return -EIO;
        }

        return size;
    }
    catch(const sql_error& e) {
        log::error("PostgreDB::query_size(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_size(): EXCEPTION (%s)", e.what());
       return -EIO;
    }

}


int PostgreDB::query_set_size(pqxx::connection* conn, int inode, int size)
{   log::debug("PostgreDB::query_set_size(inode=%d, size=%d) called", inode, size);
    char sql_buf[MAX_SQL_BUF];

    snprintf(sql_buf, MAX_SQL_BUF, "UPDATE inodes SET size=%d, mtime=date_part('epoch',now()), ctime=date_part('epoch',now()) WHERE inode=%d", (int)size, inode); 

    try {
        work action(*conn, "query_set_size");

        log::debug("PostgreDB::query_set_size(): SQL=%s", sql_buf);

        action.exec(sql_buf);
        
        action.commit();
       
        log::debug("PostgreDB::query_set_size(): inode %d size changed to %d", inode, size);

        return 0;
    }
    catch(const sql_error& e) {
        log::error("PostgreDB::query_set_size(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_set_size(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
 
}


int PostgreDB::query_mknod(connection* conn, const char* name, mode_t mode, \
                           dev_t dev, int parent)
{   log::debug("PostgreDB::query_mknod(name=\"%s\", mode=0%o, parent=%d) called", name, mode, parent);

    char sql_buf[MAX_SQL_BUF];
    int inode = -1;

    try {
        work action(*conn, "query_mknod");
 
        log::debug("PostgreDB::query_mknod(): SQL=SELECT nextval('inodes_inode_seq');");

        result res = action.exec("SELECT nextval('inodes_inode_seq');");
        if(res.size() == 0 || !res[0][0].to(inode) ) {
            log::error("PostgreDB::query_mknod() SELECT nextval('inodes_inode_seq') doesn't return next value.");
            return -EIO;
        }
        
        log::debug("PostgreDB::query_mknod(): New inode = %d", inode);

        snprintf(sql_buf, MAX_SQL_BUF, "INSERT INTO inodes(inode, mode, uid, gid, data)"
                                       " VALUES (%d, %d, %d, %d, %s)",
                                        inode, mode, fuse_get_context()->uid, fuse_get_context()->gid,
                                        (mode & S_IFREG) ? "lo_create(0)" : "NULL");

        log::debug("PostgreDB::query_mknod(): SQL=%s", sql_buf);
        action.exec(sql_buf);
                             
        if(name[0] == '/' && name[1] == '\0') { // Create the root directory.
            snprintf(sql_buf, MAX_SQL_BUF, "INSERT INTO tree (inode, name, parent) VALUES (%d, '/', NULL)", inode);
        }
        else {                   
            string base_name = sqlesc(name);
            
            snprintf(sql_buf, MAX_SQL_BUF, "INSERT INTO tree (inode, name, parent) VALUES (%d, '%s', %d)", inode, base_name.c_str(), parent);            
           }

        log::debug("PostgreDB::query_mknod(): SQL=%s", sql_buf);
             
        action.exec(sql_buf);

        action.commit();
       
        log::info("PostgreDB::query_mknod(): inode %d, corresponding to %s was created.", inode, name);
        return inode;
    }
    catch(const sql_error& e) {
        log::error("PostgreDB::query_mknod(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_mknod(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
    
}



int PostgreDB::query_getattr(connection* conn, int inode, struct stat* stbuf)
{   log::debug("PostgreDB::query_getattr(inode = %d) called", inode);

    char sql_buf[MAX_SQL_BUF];

    snprintf(sql_buf, MAX_SQL_BUF, "SELECT inode, mode, uid, gid, atime, mtime, ctime, size, nlink "
                                   "FROM inodes WHERE inode=%d", inode);

    try {
        work action(*conn, "query_getattr");
        
        log::debug("PostgreDB::query_getattr(): SQL=%s", sql_buf);

        result res = action.exec(sql_buf);
        
        if(res.size() == 0) {
            log::error("PostgreDB::query_getattr(): can not get inodes entry for inode %d", inode);
            return -ENOENT;
        }
 
        action.commit();
       
        stbuf->st_ino = atoi(res[0][0].c_str());
        stbuf->st_mode = atoi(res[0][1].c_str());
        stbuf->st_uid = atoi(res[0][2].c_str());
        stbuf->st_gid = atoi(res[0][3].c_str());
        stbuf->st_atime = atoi(res[0][4].c_str());
        stbuf->st_mtime = atoi(res[0][5].c_str());
        stbuf->st_ctime = atoi(res[0][6].c_str());
        stbuf->st_size  = atol(res[0][7].c_str());
        stbuf->st_nlink = atol(res[0][8].c_str());

        return 0;
    }
    catch(const sql_error& e) {
        log::error("PostgreDB::query_getattr(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_getattr():  EXCEPTION (%s)", e.what());
       return -EIO;
    }
}



int PostgreDB::query_readdir(connection* conn, int dir_id, void* buf, fuse_fill_dir_t filler) 
{
    char sql_buf[MAX_SQL_BUF];
    
    snprintf(sql_buf, MAX_SQL_BUF, "SELECT name FROM tree WHERE parent=%d", dir_id);
    
    try {
       work action(*conn, "query_readdir");
       
       log::debug("PostgreDB::query_readdir(): SQL=%s", sql_buf);
       
       result res = action.exec(sql_buf);
       
       action.commit();

       for(result::const_iterator it = res.begin(); it != res.end(); it++) {
           filler(buf, it[0].c_str(), NULL, 0);
       }    

       log::debug("PostgreDB::query_readdir(): successfully listed the content of directory with ID %d", dir_id);

       return 0;
    }  
    catch(const sql_error& e) {
        log::error("PostgreDB::query_readdir(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_readdir(): EXCEPTION (%s)", e.what());
       return -EIO;
    }

}



int PostgreDB::query_inuse_inc(connection* conn, int inode, int inc)
{   log::debug("PostgreDB::query_inuse_inc(inode=%d, inc=%d): called", inode, inc);

    char sql_buf[MAX_SQL_BUF];
    snprintf(sql_buf, MAX_SQL_BUF,"UPDATE inodes SET inuse=inuse+%d%s "
                                  "WHERE inode=%d", 
                                  inc, inc>0 ? ", atime=date_part('epoch',now())":"", inode);

    try {
        work action(*conn, "query_inuse_inc");
        
        log::debug("PostgreDB::query_inuse_inc(): SQL=%s", sql_buf);
        
        action.exec(sql_buf);

        action.commit();

        log::debug("PostgreDB::query_inuse_inc(): successfully incremented inode %d inuse with %d",                   
                    inode, inc);
        
        return 0;
    }
    catch(const sql_error& e) {
        log::error("PostgreDB::query_inuse_inc(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_inuse_inc(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
}



int PostgreDB::query_utime(connection* conn, int inode, struct utimbuf* time)
{   log::debug("PostgreDB::query_utime(%d) called", inode);

    char sql_buf[MAX_SQL_BUF];
    
    snprintf(sql_buf, MAX_SQL_BUF, "UPDATE inodes "
                                   "SET atime=%ld, mtime=%ld "
                                   "WHERE inode=%d", time->actime, time->modtime, inode);

    try {
        work action(*conn, "query_utime");
        
        log::debug("PostgreDB::query_utime(): SQL=%s", sql_buf);

        action.exec(sql_buf);

        action.commit();
       
        log::debug("PostgreDB::query_utime(): successfully updated inode %d atime to %d and mtime to %d",
                    inode, time->actime, time->modtime);        

        return 0;
    }
    catch(const sql_error& e) {
        log::error("PostgreDB::query_utime(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_utime(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
}



int PostgreDB::query_chmod(connection* conn, int inode, mode_t mode)
{   log::debug("PostgreDB::query_chmod(%d) called", inode);

    char sql_buf[MAX_SQL_BUF];
    
    snprintf(sql_buf, MAX_SQL_BUF, "UPDATE inodes SET mode=%d, ctime=date_part('epoch',now()) WHERE inode=%d", mode, inode);
    
    try {
        work action(*conn, "query_chmod");
      
        log::debug("PostgreDB::query_chmod(): SQL=%s", sql_buf);

        action.exec(sql_buf);
        
        action.commit();
        
        log::debug("PostgreDB::query_chmod(): successfully updated inode %d mode to %o", inode, mode);
        
        return 0;  
    }
    catch(const sql_error& e) {
        log::error("PostgreDB::query_chmod(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_chmod(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
}



int PostgreDB::query_chown(connection* conn, int inode, uid_t uid, gid_t gid)
{   log::debug("PostgreDB::query_chown(%dm uid=%d, gid=%d) called", inode, uid, gid);

    char sql_buf[MAX_SQL_BUF];
    
    snprintf(sql_buf, MAX_SQL_BUF, "UPDATE inodes SET uid=%d, gid=%d, ctime=date_part('epoch',now()) WHERE inode=%d", uid, gid, inode);
    
    try {
        work action(*conn, "query_chown");
      
        log::debug("PostgreDB::query_chown(): SQL=%s", sql_buf);

        action.exec(sql_buf);
        
        action.commit();
        
        log::debug("PostgreDB::query_chown(): successfully updated inode %d uid:gid to %dL%d", inode, uid, gid);
        
        return 0;  
    }
    catch(const sql_error& e) {
        log::error("PostgreDB::query_chown(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_chown(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
}


int PostgreDB::query_get_data_oid(pqxx::connection* conn, int inode, int* data_oid)
{   log::debug("PostgreDB::query_get_data_oid(%d) called", inode);

    int id;
    char sql_buf[MAX_SQL_BUF];
    
    snprintf(sql_buf, MAX_SQL_BUF, "SELECT data FROM inodes WHERE inode=%d", inode);
    
    try {
        work action(*conn, "query_get_data_oid");
        
        result res = action.exec(sql_buf);
        
        action.commit(); // End the transaction.

        if(res.size() == 0) 
        {   log::error("PostgreDB::query_get_data_oid(): %s did not return the 'data' field for inode %d", sql_buf, inode);
            return -EIO;
        }

        if(res[0][0].is_null()) 
        {   log::error("PostgreDB::query_get_data_oid(): data for inode %d is NULL", inode);
            return -EIO;
        }
        
        id = atoi(res[0][0].c_str());
        
        if(data_oid != NULL)
            *data_oid = id;
    
        log::debug("PostgreDB::query_get_data_oid(): returned data oid %d for inode %d", id, inode);
        return 0;
    }    
    catch(const sql_error& e) {
        log::error("PostgreDB::query_get_data_oid(): SQL ERROR (%s) for SQL=(%s) ", e.what(), e.query().c_str());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_get_data_oid(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
}



int PostgreDB::query_truncate(connection* conn, int inode, off_t size)
{   log::debug("PostgreDB::query_truncate(inode=%d, size=%d) called", inode, size);

    char sql_buf[MAX_SQL_BUF];

    int old_size = query_size(conn, inode);

    if(old_size < 0) {
        log::error("PostgreDB::query_truncate(): query_size() did not return the size for %d", inode);
        return old_size;
    }

    log::debug("PostgreDB::query_truncate(): old_size=%d", old_size);
    
    if (size==old_size)
    {   log::debug("PostgreDB::query_truncate(): size==old_size -> nothing to do");
        return 0;
    }

    if (size==0)
    {   log::debug("PostgreDB::query_truncate(): size==0 unlinking old largeobject and creating new one");
        
        try {
            snprintf(sql_buf, MAX_SQL_BUF, "SELECT lo_unlink(data) FROM inodes WHERE inode=%d;"
                                           "UPDATE inodes SET size=%d, data=lo_create(0)"
                                           ", mtime=date_part('epoch',now()), ctime=date_part('epoch',now())"
                                           " WHERE inode=%d", 
                                           inode, (int)size, inode);
            log::debug("PostgreDB::query_truncate(): SQL=%s", sql_buf);

            work action(*conn, "query_truncate");
            action.exec(sql_buf); 
            action.commit();
               
            log::info("PostgreDB::query_truncate(): inode %d size successfully changed from %d to %d bytes", inode, old_size, size);
            return 0;
        }
        catch(const sql_error& e) {
            log::error("PostgreDB::query_truncate(): SQL ERROR (%s)", e.what());
            return -EIO;
        }
        catch(const exception& e) {
            log::error("PostgreDB::query_truncate(): EXCEPTION (%s)", e.what());
            return -EIO;
        }
    }

    //! We do not yet support truncate to smaller size!=0.
    if(size != 0 || size <= old_size) {
        log::error("PostgreDB::query_truncate(): truncate of file with size %d to size %d is not yet supported", old_size, size);
        return -EIO;
    }

    int res, data_oid;
    if( (res = query_get_data_oid(conn, inode, &data_oid)) != 0 )  {
        log::error("PostgreDB::query_truncate(): query_get_data_oid() failed to get largeobject ID for inode %d", inode);
        return res;
    }
        
    ssize_t inc = size - old_size;
    off_t offset = old_size;

    try { // Increase the size of the file, by writing '0' in chunks of MAX_WRITE_CHUNK bytes at the end.
        char* buf = new char[MAX_WRITE_CHUNK];
        memset(buf, 0, MAX_WRITE_CHUNK);

        while(inc > 0) {
            int write_chunk = min(inc, MAX_WRITE_CHUNK);

            conn->perform( WriteLargeObject(data_oid, buf, write_chunk, offset, NULL) );

            offset += write_chunk;
            inc -= write_chunk;
        }

        delete[] buf;

        // Change the inode size in the inodes table.
        snprintf(sql_buf, MAX_SQL_BUF, "UPDATE inodes SET size=%d WHERE inode=%d", (int)size, inode); 
        log::debug("PostgreDB::query_truncate(): SQL=%s", sql_buf);

        work action(*conn, "query_truncate");
        action.exec(sql_buf); 
        action.commit();
               
        log::info("PostgreDB::query_truncate(): inode %d size successfully changed from %d to %d bytes", inode, old_size, size);
        return 0;
    }
    catch(const sql_error& e) {
        log::error("PostgreDB::query_truncate(): SQL ERROR (%s)", e.what());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_truncate(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
}



int PostgreDB::query_write(pqxx::connection* conn, int inode, const char* data,
                           size_t size, off_t offset)
{   log::debug("PostgreDB::query_write(inode=%d, size=%d, offset=%d) called", inode, size, offset);

    int res;
    int data_oid;

    if( (res = query_get_data_oid(conn, inode, &data_oid)) != 0 )  {
        log::debug("PostgreDB::query_write(): query_get_data_oid() failed to get largeobject ID for inode %d", inode);
        return res;
    }

    try {
        size_t new_size;
        conn->perform( WriteLargeObject(data_oid, data, size, offset, &new_size) );

        log::debug("PostgreDB::query_write(): query_write() successfully wrote %d bytes to inode %d starting from offset %d", size, inode, offset);
        
        int ret = query_set_size(conn, inode, new_size);
        if(ret != 0) return ret;

        log::debug("PostgreDB::query_write(): inode %d data, new size = %d", inode, new_size);
        return size;
    }    
    catch(const sql_error& e) {
        log::error("PostgreDB::query_write(): SQL ERROR (%s) for SQL=(%s) ", e.what(), e.query().c_str());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_write(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
}



int PostgreDB::query_read(pqxx::connection* conn, int inode, char* data, \
                          size_t size, off_t offset)
{   log::debug("PostgreDB::query_read(inode=%d, size=%d, offset=%d) called", inode, size, offset);

    int res;
    int data_oid;

    if( (res = query_get_data_oid(conn, inode, &data_oid)) != 0 )  {
        log::debug("PostgreDB::query_read(): query_get_data_oid() failed to get largeobject ID for inode %d", inode);
        return res;
    }

    try {
        conn->perform( ReadLargeObject(data_oid, data, size, offset) );

        log::debug("PostgreDB::query_read(): successfully read %d bytes from inode %d starting from offset %d", size, inode, offset);

        return size;
    }    
    catch(const sql_error& e) {
        log::error("PostgreDB::query_read(): SQL ERROR (%s) for SQL=(%s) ", e.what(), e.query().c_str());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_read(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
}



int PostgreDB::query_rm_tree_entry(pqxx::connection* conn, int tree_id)
{   log::debug("PostgreDB::query_rm_tree_entry(tree_id = %d) called", tree_id);

    char sql_buf[MAX_SQL_BUF];
    
    snprintf(sql_buf, MAX_SQL_BUF, "DELETE FROM tree WHERE id=%d", tree_id);
    
    try {
        work action(*conn, "query_rm_tree_entry");
        
        result res = action.exec(sql_buf);
        
        action.commit(); // End the transaction.
    
        log::debug("PostgreDB::query_rm_tree_entry(): successfully deleted tree entry with id %d", tree_id);
        return 0;
    }    
    catch(const sql_error& e) {
        log::error("PostgreDB::query_rm_tree_entry(): SQL ERROR (%s) for SQL=(%s) ", e.what(), e.query().c_str());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_rm_tree_entry(): EXCEPTION (%s)", e.what());
       return -EIO;
    }
}



int PostgreDB::query_purge_deleted(pqxx::connection* conn, int inode)
{   log::debug("PostgreDB::query_purge_deleted(tree_id = %d) called", inode);

    char sql_buf[MAX_SQL_BUF];
    
    snprintf(sql_buf, MAX_SQL_BUF, "DELETE FROM inodes WHERE inode=%d AND inuse=0 AND deleted=1", inode);
    
    try {
        work action(*conn, "query_purge_deleted");
        
        result res = action.exec(sql_buf);
        
        action.commit(); // End the transaction.
    
        return 0;
    }    
    catch(const sql_error& e) {
        log::error("PostgreDB::query_purge_deleted(): SQL ERROR (%s) for SQL=(%s) ", e.what(), e.query().c_str());
        return -EIO;
    }
    catch(const exception& e) {
       log::error("PostgreDB::query_purge_deleted(): EXCEPTION (%s)", e.what());
       return -EIO;
    }

}

//************************** WriteLargeObject Implementation ************************** 

WriteLargeObject::WriteLargeObject(int data_oid, const char* data, size_t size, off_t offset, size_t* new_size):
        pqxx::transactor<>("WriteLargeObject"), 
        my_object()
{
    this->data_oid = data_oid;
    this->data = data;
    this->size = size;
    this->offset = offset;

    this->new_size = new_size;
}

/**
 * 
 *  Gets write access to the large object with an id 'oid'. Writes to the object and modifies the size.
 */
void WriteLargeObject::operator()(argument_type& T) {
    
    largeobjectaccess access(T, data_oid, ios::out);

    access.seek(offset, ios::beg);
    access.write(data, size);

    if(new_size != NULL) { // Get the new size.
        access.seek(0, ios::end);
        *new_size = access.tell();
    }
}

//************************** ReadLargeObject Implementation ************************** 

ReadLargeObject::ReadLargeObject(int data_oid, char* data, size_t size, off_t offset):
        pqxx::transactor<>("ReadLargeObject"), 
        my_object()
{
    this->data_oid = data_oid;
    this->data = data;
    this->size = size;
    this->offset = offset;
}

/**
 * 
 *  Gets read access to the large object with an id 'oid'. Reads and stores the information in the data member of the      
 *  LargeObject
 */
void ReadLargeObject::operator()(argument_type& T) {
    
    largeobjectaccess access(T, data_oid, ios::in);

    access.seek(offset, ios::beg);
    access.read(data, size);
}

